<script>

import WithDialog from '@/components/WithDialog/withDialog'
import Item from './fieldModifyHistory'

import { keyMap } from './index.js'
import { fieldModifyHistory } from '@/api/personnel'
import { getEducation, getSchool, getDept, getPosition, getNation, getPolitic, getMarriage, getBank } from '@/api/basic'
import { atLeast, isAvailable, isObject } from '@/utils/kris_utils'

export default {
  components: {
    WithDialog,
    Item
  },
  props: {
    userID: {
      required: true,
      default: null
    }
  },
  data() {
    return {
      fields: [],
      rawData: [],
      allHistory: [],
      keyMap,
      resultDialog: {
        isLoading: false,
        visible: false
      },
      historyDialog: {
        isLoading: true,
        visible: false
      },
      previewDialog: {
        data: null,
        titie: '修改详情',
        visible: false
      },
      allHistoryPagination: {
        size: 10,
        current: 1,
        total: 0
      },
      pagination: {
        size: 10,
        current: 1,
        total: 0
      },
      options: {
        gender: [
          { label: '男', value: 1 },
          { label: '女', value: 0 }
        ],
        nation: [],
        marriageStatus: [],
        educationLevel: [],
        registeredResidenceType: [
          { label: '农村', value: 1 },
          { label: '城市', value: 0 }
        ],
        educationType: [
          { label: '成人教育', value: 1 },
          { label: '自考', value: 0 },
          { label: '统招', value: 2 }
        ],
        school: [],
        bank: [],
        politicalStatus: [],
        domicile: [],
        post: [],
        employeeType: [
          { label: '正式员工', value: 0 },
          { label: '实习员工', value: 1 },
          { label: '试用员工', value: 2 }
        ],
        department: [],
        status: [
          { label: '在职', value: 1 },
          { label: '离职', value: 0 }
        ],
        departSalaryStatusOptions: [
          { label: '已结清', value: 1 },
          { label: '未结清', value: 0 }
        ],
        leader: [], // x
        apartment: []// x
      }
    }
  },
  computed: {
    genderMap() {
      return this.makeMap(this.options.gender)
    },
    schoolMap() {
      return this.makeMap(this.options.school)
    },
    registeredResidenceTypeMap() {
      return this.makeMap(this.options.registeredResidenceType)
    },
    nationMap() {
      return this.makeMap(this.options.nation)
    },
    politicsMap() {
      return this.makeMap(this.options.politicalStatus)
    },
    educationTypeMap() {
      return this.makeMap(this.options.educationType)
    },
    marriageStatusMap() {
      return this.makeMap(this.options.marriageStatus)
    },
    educationLevelMap() {
      return this.makeMap(this.options.educationLevel)
    },
    statusMap() {
      return this.makeMap(this.options.status)
    },
    bankMap() {
      return this.makeMap(this.options.bank)
    },
    postMap() {
      return this.makeMap(this.options.post)
    },
    employeeTypeMap() {
      return this.makeMap(this.options.employeeType)
    },
    departSalaryStatusMap() {
      return this.makeMap(this.options.departSalaryStatusOptions)
    },
    setsForFormater() {
      return {
        gender: this.genderMap,
        school_id: this.schoolMap,
        registered_residence: this.registeredResidenceTypeMap,
        nation_id: this.nationMap,
        politic_id: this.politicsMap,
        education_nature: this.educationTypeMap,
        education_id: this.educationLevelMap,
        marital_id: this.marriageStatusMap,
        bank_id: this.bankMap,
        identity: this.employeeTypeMap,
        job_status: this.statusMap,
        position_id: this.postMap,
        department_id: this.options.department,
        quit_salary_status: this.departSalaryStatusMap
      }
    },
    fieldOptions() {
      return Object
        .entries(this.keyMap)
        .filter(([key, field]) => !field.disabled)
        .map(item => {
          const [key, field] = item
          return {
            label: field.label,
            value: key
          }
        })
    },
    originalKeyMap() {
      return Object.fromEntries(Object.entries(this.keyMap)
        .map(([key, value]) => {
          return [value.mapTo, value]
        }))
    },
    data() {
      return this.rawData.map(this.formatItem)
    }
  },
  created() {
    this.initData()
  },
  methods: {
    handlePageChange(currentPage) {
      this.pagination.current = currentPage
      this.fetchModifyHistory()
    },
    handlePageSizeChange(size) {
      this.pagination.size = size
      this.fetchModifyHistory()
    },
    handleAllHistoryPageChange(currentPage) {
      this.allHistoryPagination.current = currentPage
      this.fetchAllModifyHistory()
    },
    handleAllHistoryPageSizeChange(size) {
      this.allHistoryPagination.size = size
      this.fetchAllModifyHistory()
    },
    formatItem(item) {
      const { created_at, table, id, field, operator } = item

      return {
        id,
        table,
        operator: {
          name: operator?.username,
          id: operator?.id,
          avatar: operator?.avatar
        },
        title: created_at,
        fields: field.map(f => {
          /**
                     * 因为后端返回的数据的字段值都会用JSON包一层属性{value:Data}
                     * 所以parseValue就是用来解析从而拿到原始值 可以理解为剥壳
                     * 而字段设置都会有一个formatter(可选)就是用来处理数据
                     * 相当于   data -> formatter(如果有的话) -> 显示的值
                     * 如果字段设置有component的话会把整个字段当props传入否则直接展示
                     */
          const fieldCfg = this.originalKeyMap[f.field]

          if (!isObject(fieldCfg)) { return null }

          const fallback = '-'

          const newValue = this.parseValue(f['new'])
          const oldValue = this.parseValue(f['old'])
          let newValueFormatted = null
          let oldValueFormatted = null

          const hasFormatter = typeof fieldCfg.formatter === 'function'
          if (hasFormatter) {
            newValueFormatted = fieldCfg.formatter(fieldCfg, newValue, fallback, { sets: this.setsForFormater })
            oldValueFormatted = fieldCfg.formatter(fieldCfg, oldValue, fallback, { sets: this.setsForFormater })
          }

          return {
            fieldCfg,
            before: hasFormatter ? oldValueFormatted : oldValue,
            after: hasFormatter ? newValueFormatted : newValue
          }
        })
      }
    },
    viewDetails(item, index) {
      const data = this.formatItem(item)
      this.previewDialog.titie = `第 ${this.timesFormatter(index)} 次修改-修改详情`
      this.previewDialog.data = data
      this.previewDialog.visible = true
    },
    makeMap(options, valueKey = 'value') {
      const m = new Map()

      for (const item of options) {
        m.set(item[valueKey], item)
      }

      return m
    },
    parseValue(val) {
      try {
        const tmp = JSON.parse(val)
        if ('value' in tmp) { return tmp.value }

        return null
      } catch (e) {
        return null
      }
    },
    async fetchAllModifyHistory() {
      try {
        this.historyDialog.isLoading = true
        const table = ['user_details', 'user_companys']

        const params = {
          table: JSON.stringify(table),
          user_id: this.userID,
          sort: 'asc',
          paginate: this.allHistoryPagination.size,
          page: this.allHistoryPagination.current
        }

        const result = await fieldModifyHistory(params)

        this.allHistoryPagination.total = result?.meta?.total ?? 0
        this.allHistory = result.data

        this.historyDialog.isLoading = false
      } catch (e) {
        this.historyDialog.isLoading = false
      }
    },
    async fetchModifyHistory() {
      try {
        this.resultDialog.isLoading = true
        const table = ['user_details', 'user_companys']
        const fields = this.fields.map(field => this.keyMap[field].mapTo)

        const params = {
          table: JSON.stringify(table),
          field: JSON.stringify(fields),
          user_id: this.userID,
          sort: 'desc',

          page: this.pagination.current
        }

        const result = await fieldModifyHistory(params)

        this.resultDialog.isLoading = false

        this.pagination.total = result?.meta?.total ?? 0
        this.rawData = result.data
      } catch (e) {
        this.resultDialog.isLoading = false
      }
    },
    departmentFormatter(options = [], childrenKey = 'children') {
      const result = []

      for (const i in options) {
        const option = options[i]

        const { id, name } = option
        const tmp = { label: name, value: id }

        if (Array.isArray(option[childrenKey]) && option[childrenKey].length > 0) { tmp['children'] = this.departmentFormatter(option[childrenKey], childrenKey) }

        result.push(tmp)
      }

      return result
    },
    closeResultDialog() {
      this.pagination.current = 1
      this.resultDialog.visible = false
    },
    openResultDialog() {
      this.fetchModifyHistory()
      this.resultDialog.visible = true
    },
    beforeClose(e) {
      this.pagination.current = 1
      e(true)
    },

    openHistoryDialog() {
      this.historyDialog.visible = true
      this.fetchAllModifyHistory()
    },
    closeHistoryDialog() {
      this.allHistoryPagination.current = 1
      this.historyDialog.visible = false
    },
    historyDialogBeforeClose(e) {
      this.allHistoryPagination.current = 1
      e(true)
    },

    timesFormatter(index) {
      const { current, size } = this.allHistoryPagination
      return (index + 1) + (current * size - size)
    },

    // --------------------------
    async getEducationOptions() {
      const result = await getEducation()
      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error('加载学历选项失败') }

      this.options.educationLevel = result.data.map(item => {
        return {
          label: item.name,
          value: item.id
        }
      })
    },
    async getSchoolOptions(kw) {
      const result = await getSchool({ search: kw ?? '' })
      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error('加载学校选项失败') }

      this.options.school = result.data.map(item => {
        return {
          label: item.school_name,
          value: item.id
        }
      })
    },
    async getPolitics() {
      const result = await getPolitic()
        .catch(err => {
          throw new Error('获取政治面貌选项失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取政治面貌选项失败')) }

      this.options.politicalStatus = result.data.map(item => ({ label: item.name, value: item.id }))
    },
    async getNations() {
      const result = await getNation()
        .catch(err => {
          throw new Error('获取民族选项失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取婚姻状态选项失败')) }

      this.options.nation = result.data.map(item => ({ label: item.nation, value: item.id }))
    },
    async getMarriageStatuses() {
      const result = await getMarriage()
        .catch(err => {
          throw new Error('获取婚姻状态选项失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取婚姻状态选项失败')) }

      this.options.marriageStatus = result.data.map(item => ({ label: item.name, value: item.id }))
    },
    async getDepartments() {
      const result = await getDept()
        .catch(err => {
          throw new Error('获取部门信息失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取部门信息失败')) }

      this.options.department = this.departmentFormatter(result.data)
    },
    async getPosts() {
      const result = await getPosition()
        .catch(err => {
          throw new Error('获取岗位信息失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取岗位信息失败')) }

      this.options.post = result.data.map(item => ({ label: item.name, value: item.id }))
    },
    async getBanks(kw) {
      const result = await getBank()
        .catch(err => {
          throw new Error('获取银行选项失败')
        })

      if (result.code !== 200 || !Array.isArray(result.data)) { throw new Error(value(result, 'message', '获取银行选项失败')) }

      this.options.bank = result.data.map(item => ({ label: item.bankName, value: item.id }))
    },
    async loadData() {
      await Promise.allSettled([
        this.fetchAllModifyHistory(),
        this.getSchoolOptions(),
        this.getEducationOptions(),
        this.getMarriageStatuses(),
        this.getNations(),
        this.getPolitics(),
        this.getBanks(),
        this.getPosts(),
        this.getDepartments()
      ])
    },
    async initData() {
      await this.loadData()
    }
  }
}
</script>

<template>
  <div class="field-modify-history-container">
    <el-form :inline="true" class="demo-form-inline">
      <el-form-item>
        <div class="search-box">
          <div class="warp">
            <el-select
              v-model="fields"
              multiple
              placeholder="按员工字段搜索历史记录"
              filterable
              style="width: 100%;"
            >
              <el-option
                v-for="option in fieldOptions"
                :key="option.value"
                :label="option.label"
                :value="option.value"
              />
            </el-select>
          </div>
          <el-button type="primary" @click="openResultDialog">查询</el-button>
        </div>
        <div>
          <el-button type="text" :loading="historyDialog.isLoading" @click="openHistoryDialog">已查询到 {{ allHistoryPagination.total }} 次修改（点击查看）</el-button>
        </div>
      </el-form-item>
    </el-form>

    <WithDialog
      title="修改记录详情"
      width="50%"
      :show-cancel-btn="false"
      :visible.sync="resultDialog.visible"
      :before-close="beforeClose"
      @confirm="closeResultDialog"
    >
      <div v-loading="resultDialog.isLoading" style="padding: 10px;background-color: #f0f0f0;border-radius: 10px;">
        <div v-if="data.length > 0" class="history">
          <Item v-for="item in data" :key="item.id" :data="item" />
        </div>
        <el-empty v-else description="暂无修改记录" />
      </div>
      <el-pagination
        hide-on-single-page
        layout="total, sizes, prev, pager, next, jumper"
        :current-page="pagination.current"
        :page-sizes="[10, 50, 100]"
        :page-size="pagination.size"
        :total="pagination.total"
        :disabled="resultDialog.isLoading"
        @size-change="handlePageSizeChange"
        @current-change="handlePageChange"
      />
    </WithDialog>

    <WithDialog
      title="修改记录"
      width="30%"
      :show-cancel-btn="false"
      :visible.sync="historyDialog.visible"
      :before-close="historyDialogBeforeClose"
      @confirm="closeHistoryDialog"
    >
      <el-dialog
        width="40%"
        :title="previewDialog.titie"
        :visible.sync="previewDialog.visible"
        append-to-body
      >
        <div v-if="previewDialog.data" style="height: 60vh;overflow-y: scroll;overflow-x: hidden;">
          <Item :data="previewDialog.data" />
        </div>
      </el-dialog>

      <div v-loading="historyDialog.isLoading" style="padding: 10px;background-color: #f0f0f0;border-radius: 10px;">
        <div v-if="allHistory.length > 0">
          <div v-for="(item,index) in allHistory" :key="item.id" class="history-item" @click="viewDetails(item,index)">
            <div>
              <i class="el-icon-edit-outline" />
                            &nbsp;
              <span style="color: #454545;font-weight: bold;">第{{ timesFormatter(index) }}次修改</span>
            </div>
            <span style="color: #8e8e8e;">{{ item.created_at }}</span>
          </div>
        </div>
        <el-empty v-else description="暂无修改记录" />
      </div>
      <el-pagination
        hide-on-single-page
        layout="total, sizes, prev, pager, next, jumper"
        :current-page="allHistoryPagination.current"
        :page-sizes="[10, 50, 100]"
        :page-size="allHistoryPagination.size"
        :total="allHistoryPagination.total"
        :disabled="allHistoryPagination.isLoading"
        @size-change="handleAllHistoryPageSizeChange"
        @current-change="handleAllHistoryPageChange"
      />
    </WithDialog>
  </div>
</template>

<style lang="scss">
    .field-modify-history-container {
        .el-form-item {
            margin-bottom: 0;
        }
        .search-box {
            display: flex;
            .warp {
                flex: 1;
                padding-right: 10px;
            }
        }
        .history {
            height: 60vh;
            overflow-y: scroll;
            overflow-x: hidden;
        }
        .history-item {
            padding: 14px 10px;
            background-color: white;
            margin-top: 10px;
            border-radius: 6px;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;

            &:first-child {
                margin-top: 0;
            }
        }
    }
</style>
